//
//  UICollectionViewFlowLayout+MKUI.m
//  MKUI
//
//  Created by 苏尚进 on 2020/8/30.
//  Copyright © 2020 moon. All rights reserved.
//

#import "UICollectionViewFlowLayout+MKUI.h"
#import "UIScrollView+MKUI.h"
#import "CGGeometry+MKUI.h"
#import "UICollectionViewFlowLayout+MKUI.h"

@implementation UICollectionViewFlowLayout (MKUI)
- (id<UICollectionViewDelegateFlowLayout>)mk_flowLayoutDelegate{
    id<UICollectionViewDelegateFlowLayout> delegate;
    if([self.collectionView.delegate conformsToProtocol:@protocol(UICollectionViewDelegateFlowLayout)]){
        delegate = (id<UICollectionViewDelegateFlowLayout>)self.collectionView.delegate;
    }
    return delegate;
}
- (CGSize)mk_sizeForItemAtIndexPath:(NSIndexPath *)indexPath{
    id<UICollectionViewDelegateFlowLayout> delegate = self.mk_flowLayoutDelegate;
    return [delegate respondsToSelector:@selector(collectionView:layout:sizeForItemAtIndexPath:)]?[delegate collectionView:self.collectionView layout:self sizeForItemAtIndexPath:indexPath]:self.itemSize;
}
- (UIEdgeInsets)mk_insetForSectionAtIndex:(NSInteger)index{
    UICollectionView *collectionView = self.collectionView;
    id<UICollectionViewDelegateFlowLayout> delegate = self.mk_flowLayoutDelegate;
    return [delegate respondsToSelector:@selector(collectionView:layout:insetForSectionAtIndex:)]?[delegate collectionView:collectionView layout:self insetForSectionAtIndex:index]:self.sectionInset;
}
- (CGFloat)mk_minimumLineSpacingForSectionAtIndex:(NSInteger)index{
    UICollectionView *collectionView = self.collectionView;
    id<UICollectionViewDelegateFlowLayout> delegate = self.mk_flowLayoutDelegate;
    return [delegate respondsToSelector:@selector(collectionView:layout:minimumLineSpacingForSectionAtIndex:)]?[delegate collectionView:collectionView layout:self minimumLineSpacingForSectionAtIndex:index]:self.minimumLineSpacing;
}
- (CGFloat)mk_minimumInteritemSpacingForSectionAtIndex:(NSInteger)index{
    UICollectionView *collectionView = self.collectionView;
    id<UICollectionViewDelegateFlowLayout> delegate = self.mk_flowLayoutDelegate;
    return [delegate respondsToSelector:@selector(collectionView:layout:minimumInteritemSpacingForSectionAtIndex:)]?[delegate collectionView:collectionView layout:self minimumInteritemSpacingForSectionAtIndex:index]:self.minimumInteritemSpacing;
}
- (CGSize)mk_referenceSizeForFooterInSection:(NSInteger)index{
    UICollectionView *collectionView = self.collectionView;
    id<UICollectionViewDelegateFlowLayout> delegate = self.mk_flowLayoutDelegate;
    return [delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForFooterInSection:)]?[delegate collectionView:collectionView layout:self referenceSizeForFooterInSection:index]:self.footerReferenceSize;
}
- (CGSize)mk_referenceSizeForHeaderInSection:(NSInteger)index{
    UICollectionView *collectionView = self.collectionView;
    id<UICollectionViewDelegateFlowLayout> delegate = self.mk_flowLayoutDelegate;
    return [delegate respondsToSelector:@selector(collectionView:layout:referenceSizeForHeaderInSection:)]?[delegate collectionView:collectionView layout:self referenceSizeForHeaderInSection:index]:self.headerReferenceSize;
}

- (CGRect)mk_contentBoundsForSectionAtIndex:(NSInteger)index{
    UICollectionView *collectionView = self.collectionView;
    UIEdgeInsets insets = [self mk_insetForSectionAtIndex:index];
    CGRect bounds = collectionView.mk_contentBounds;
    bounds.origin = CGPointZero;
    CGRect b = UIEdgeInsetsInsetRect(bounds, insets);
    b.origin = CGPointZero;
    return b;
}
@end
@implementation UICollectionViewFlowLayout (MKUI_SizeFits)
- (CGSize)mk_sizeThatFits:(CGSize)originBoundsSize{
    CGSize size = originBoundsSize;
    UICollectionViewFlowLayout *flowlayout = self;
    UICollectionViewScrollDirection direction = flowlayout.scrollDirection;
    
    MKCGAxis axis = direction==UICollectionViewScrollDirectionVertical?MKCGAxisX:MKCGAxisY;
    MKCGAxis axisR = MKCGAxisReverse(axis);
    MKCGSizeSetLength(&size, axisR, 99999999);
    
    CGRect originBounds = self.collectionView.bounds;
    CGRect bounds = originBounds;
    bounds.size = originBoundsSize;
    self.collectionView.bounds = bounds;
    
    CGSize sizeFits = CGSizeZero;
    UIEdgeInsets insets = self.collectionView.mk_adjustedContentInset;
    size.width -= insets.left+insets.right;
    size.height -= insets.top+insets.bottom;
    
    //由于headerReferenceSize和footerReferenceSize会受bounds尺寸影响，因此要先算出bounds的最合适值，然后再计算head、foot的最合适尺寸
    //由于cell在originBoundsSize限制下，计算出适合的尺寸。这个尺寸会受originBoundsSize影响，在后续真实布局中，originBoundsSize的值可能会改变。因此要二次计算cell的最合适尺寸
    //第一次计算所有cell的最合适尺寸
    CGSize allCellsSize = [self __mk_allCellsSizeThatFitsCellBoundsSize:size];//所有cell占用的总区域尺寸
    //如果allCellsSize限制值!=size限制值，代表cell动态计算时，限定的size变更了，需要二次计算
    if(MKCGSizeGetLength(allCellsSize, axis)!=MKCGSizeGetLength(size,axis)){
        CGSize boundsSize = size;
        MKCGSizeSetLength(&boundsSize, axis, MKCGSizeGetLength(allCellsSize, axis));
        
        //更新collectionView的尺寸
        CGRect newBounds = originBounds;
        newBounds.size = originBoundsSize;
        MKCGRectSetLength(&newBounds, axis, MKCGSizeGetLength(allCellsSize, axis)+MKUIEdgeInsetsGetEdge(insets, axis, MKUIEdgeInsetsMin)+MKUIEdgeInsetsGetEdge(insets, axis, MKUIEdgeInsetsMax));
        self.collectionView.bounds = newBounds;
        
        allCellsSize = [self __mk_allCellsSizeThatFitsCellBoundsSize:boundsSize];
    }
    sizeFits = allCellsSize;
    
    sizeFits.width += insets.left+insets.right;
    sizeFits.height += insets.top+insets.bottom;

    //在计算出cell的占用区域后，在此基础上，计算head和foot的最合适尺寸
    MKCGSizeSetLength(&sizeFits, axis, ceil(MKCGSizeGetLength(sizeFits, axis)));//先消除浮点误差
    MKCGRectSetLength(&bounds, axis, MKCGSizeGetLength(sizeFits, axis));
    self.collectionView.bounds = bounds;
    
    NSInteger numberOfSections = [self.collectionView.dataSource numberOfSectionsInCollectionView:self.collectionView];
    for (int i=0; i<numberOfSections; i++) {
        CGSize headerReferenceSize = [flowlayout mk_referenceSizeForHeaderInSection:i];
        CGSize footerReferenceSize = [flowlayout mk_referenceSizeForFooterInSection:i];
        
        MKCGSizeSetLength(&sizeFits, axisR,MKCGSizeGetLength(sizeFits, axisR)+MKCGSizeGetLength(headerReferenceSize, axisR)+MKCGSizeGetLength(footerReferenceSize, axisR));
    }
    
    //消除浮点误差
    sizeFits.width = ceil(sizeFits.width);
    sizeFits.height = ceil(sizeFits.height);
//    NSLog(@"sizeFit:%@",NSStringFromCGSize(sizeFits));
    self.collectionView.bounds = originBounds;
    return sizeFits;
}

//size为cell的限制区域，不包含contentInsets
- (CGSize)__mk_allCellsSizeThatFitsCellBoundsSize:(CGSize)size{
    UICollectionViewFlowLayout *flowlayout = self;
    UICollectionViewScrollDirection direction = flowlayout.scrollDirection;
    MKCGAxis X = direction==UICollectionViewScrollDirectionVertical?MKCGAxisX:MKCGAxisY;
    MKCGAxis Y = MKCGAxisReverse(X);
    MKCGSizeSetLength(&size, Y, 99999999);
    
    CGSize allCellsSize = CGSizeZero;//所有cell占用的总区域尺寸,包含了sectionInsets
    NSInteger numberOfSections = [self.collectionView.dataSource numberOfSectionsInCollectionView:self.collectionView];
    for (int i=0; i<numberOfSections; i++) {
        CGFloat minimumLineSpacing = [flowlayout mk_minimumLineSpacingForSectionAtIndex:i];
        CGFloat minimumInteritemSpacing = [flowlayout mk_minimumInteritemSpacingForSectionAtIndex:i];
        UIEdgeInsets sectionInset = [flowlayout mk_insetForSectionAtIndex:i];
        CGSize boundSize = size;
        boundSize.width -= sectionInset.left+sectionInset.right;
        boundSize.height -= sectionInset.top+sectionInset.bottom;
        
        CGFloat interitemSpacing = X==MKCGAxisX?minimumInteritemSpacing:minimumLineSpacing;
        CGFloat lineSpacing = X==MKCGAxisX?minimumLineSpacing:minimumInteritemSpacing;
        NSInteger itemCount = [self.collectionView numberOfItemsInSection:i];
        CGSize sectionFitSize = CGSizeZero;
        CGSize limitSize = boundSize;
        CGFloat maxHeight = 0;//元素的最大高度
        NSMutableArray<NSNumber *> *widths = [[NSMutableArray alloc] initWithCapacity:itemCount];
        CGFloat maxWidth = 0;//每行的最大宽度
        NSMutableArray<NSNumber *> *heights = [[NSMutableArray alloc] initWithCapacity:itemCount];
        NSInteger numberOfItems = [self.collectionView numberOfItemsInSection:i];
        for (int j=0; j<numberOfItems; j++) {
            NSIndexPath *p = [NSIndexPath indexPathForItem:j inSection:i];
            CGSize itemSize = [self mk_sizeForItemAtIndexPath:p];
            
            //消除itemSize的浮点误差，否则有可能导致collectview在布局时，因为浮点误差，一行会少布局一个元素
            itemSize.width = ceil(itemSize.width);
            itemSize.height = ceil(itemSize.height);
            
            CGFloat w = MKCGSizeGetLength(itemSize, X);
            if(w>0){
                MKCGSizeSetLength(&limitSize, X, MKCGSizeGetLength(limitSize, X)-w);
                if(MKCGSizeGetLength(limitSize, X)<0){//当前行已经放不了，需要另起一行
                    CGFloat sumWidth = (widths.count-1)*interitemSpacing;//元素的总长度
                    for (NSNumber *l in widths) {
                        sumWidth += [l floatValue];
                    }
                    maxWidth = MAX(maxWidth,sumWidth);
                    [heights addObject:@(maxHeight)];
                    
                    MKCGSizeSetLength(&limitSize, X, MKCGSizeGetLength(boundSize, X)-w);
                    MKCGSizeSetLength(&limitSize, Y, MKCGSizeGetLength(limitSize, Y)-maxHeight-lineSpacing);
                    maxHeight = 0;
                    [widths removeAllObjects];
                }
                MKCGSizeSetLength(&limitSize, X, MKCGSizeGetLength(limitSize, X)-interitemSpacing);
                maxHeight = MAX(maxHeight,MKCGSizeGetLength(itemSize, Y));
                [widths addObject:@(w)];
            }
        }
        
        if(widths.count){//处理最后一行
            CGFloat sumWidth = (widths.count-1)*interitemSpacing;//元素的总长度
            for (NSNumber *l in widths) {
                sumWidth += [l floatValue];
            }
            maxWidth = MAX(maxWidth,sumWidth);
            [heights addObject:@(maxHeight)];
        }
        if(heights.count>0){
            CGFloat sumHeight = (heights.count-1)*lineSpacing;//元素的总长度
            for (NSNumber *l in heights) {
                sumHeight += [l floatValue];
            }
            MKCGSizeSetLength(&sectionFitSize, X, maxWidth);
            MKCGSizeSetLength(&sectionFitSize, Y, sumHeight);
        }
        
        sectionFitSize.width += sectionInset.left+sectionInset.right;
        sectionFitSize.height += sectionInset.top+sectionInset.bottom;
        //
        MKCGSizeSetLength(&allCellsSize, X, MAX(MKCGSizeGetLength(allCellsSize, X),MKCGSizeGetLength(sectionFitSize, X)));
        MKCGSizeSetLength(&allCellsSize,Y,MKCGSizeGetLength(allCellsSize, Y)+MKCGSizeGetLength(sectionFitSize, Y));
    }
    return allCellsSize;
}
@end

@implementation UICollectionView (MKUI_UICollectionViewFlowLayout)
- (UICollectionViewFlowLayout *)mk_collectionViewFlowLayout{
    if([self.collectionViewLayout isKindOfClass:[UICollectionViewFlowLayout class]]){
        return (UICollectionViewFlowLayout *)self.collectionViewLayout;
    }
    return nil;
}
@end
